<template>
	<view @click="showCity = !props.disabled ? !showCity : false">
		<!-- #ifdef APP-NVUE -->
		<view :eventPenetrationEnabled="true">
			<slot></slot>
		</view>
		<!-- #endif -->
		<!-- #ifndef APP-NVUE -->
		<slot></slot>
		<!-- #endif -->
		<zh-drawer :zIndex="props.zIndex" :inContent="props.inContent" :disabbleScroll="true" :round="props.round" ref="drawer"
			:height="dHeight" :closeable="true" placement="bottom" :overlayClick="true" :duration="100"
			@open="drawerOpen" @cancel="cancel" @ok="confirm" :show="showCity" :okColor="_color" title="请选择"
			ok-text="确认">
			<template #title v-if="props.showSearch">
				<zh-input suffix="tmicon-search" placeholder="请输入搜索内容" :showClear="true" v-model="searchText"
					:transprent="false" style="width: 500rpx"></zh-input>
			</template>
			<zh-sheet :margin="[0, 0]" :height="dHeight - (store.orientation === 'landscape'?180:220)">
				<view class="mb-24 mx-24 round-3 overflow">
					<zh-radio-group direction="col" align="left" :max="1" v-if="props.mode === 'single'"
						v-model="value">
						<view style="width: 100%">
							<z-paging ref="paging" :fixed="false" :height="dHeight - (store.orientation === 'landscape'?180:220) + 'rpx'" v-model="pagingList"
								@query="onQueryList" :show-scrollbar="false">
								<template v-slot:empty>
									<zh-result :showBtn="false" title="没有可供选择的数据" subTitle="请重新输入关键字搜索"></zh-result>
								</template>
								<z-paging-cell v-for="(item, index) in pagingList"
									:key="typeof item == 'string' ? item : item[props.fieldNames.value]">
									<view class="flex-row-center-between" style="padding: 30rpx 0">
										<view style="width: 100%" @click="radioClick(item)">
											<zh-text :fontSize="30"
												:color="(typeof item == 'string' ? item : item[props.fieldNames.value]) == value ? 'primary' : ''"
												:label="typeof item == 'string' ? item : item[props.fieldNames.label]"></zh-text>
										</view>
										<zh-radio :value="typeof item == 'string' ? item : item[props.fieldNames.value]"
											@change="radioChange($event, item)"></zh-radio>
									</view>
									<zh-divider :margin="[0, 0]"></zh-divider>
								</z-paging-cell>
							</z-paging>
						</view>
					</zh-radio-group>
					<zh-checkbox-group direction="col" align="left" :max="props.max" v-if="props.mode === 'multiple'"
						v-model="value">
						<view style="width: 100%">
							<z-paging ref="paging" :fixed="false" :height="dHeight - 230 + 'rpx'" @query="onQueryList"
								v-model="pagingList" :show-scrollbar="false">
								<template v-slot:empty>
									<zh-result :showBtn="false" title="没有可供选择的数据" subTitle="请重新输入关键字搜索"></zh-result>
								</template>
								<z-paging-cell v-for="(item, index) in pagingList"
									:key="typeof item == 'string' ? item : item[props.fieldNames.value]">
									<view class="flex-row-center-between" style="padding: 30rpx 0">
										<view style="width: 100%" @click="checkboxClick(item)">
											<zh-text :fontSize="30"
												:color="value && value.includes(typeof item == 'string' ? item : item[props.fieldNames.value]) ? 'primary' : ''"
												:label="typeof item == 'string' ? item : item[props.fieldNames.label]"></zh-text>
										</view>
										<zh-checkbox @change="checkboxChange($event, item)"
											:value="typeof item == 'string' ? item : item[props.fieldNames.value]"></zh-checkbox>
									</view>
									<zh-divider :margin="[0, 0]"></zh-divider>
								</z-paging-cell>
							</z-paging>
						</view>
					</zh-checkbox-group>
				</view>
			</zh-sheet>
			<zh-button label="确认选择" block :margin="[32, 12]" :height="64" :color="_color" :linear="props.linear"
				:linear-deep="props.linearDeep" @click="confirm" :round="props.btnRound">
			</zh-button>
			<view :style="{ height: sysinfo.bottomSafe + 'px' }"></view>
		</zh-drawer>
	</view>
</template>
<script lang="ts" setup>
	import { PropType, Ref, ref, watchEffect, onMounted, getCurrentInstance, computed, toRaw, inject, nextTick, watch } from 'vue';
	import { custom_props } from '@/tool/lib/minxs';
	import { toLine } from '@/common/utils/util';
	import http from '@/common/utils/http';
	import { useWindowInfo } from '@/tool/useFun/useWindowInfo'
	import systemConfigStore from '@/store/modules/systemConfigStore';
	const store = systemConfigStore();
	const drawer = ref<any>(null);
	const emits = defineEmits(['update:show', 'update:modelValue', 'update:modelStr', 'confirm', 'cancel', 'close', 'open', 'search']);
	const props = defineProps({
		...custom_props,
		fieldNames: {
			type: Object,
			default: () => {
				return { label: 'dictValue', value: 'dictKey', children: 'children' };
			},
		},
		lazy: {
			type: Boolean,
			default: false,
		},
		//	使单选模式可搜索
		showSearch: {
			type: Boolean,
			default: true,
		},
		//可v-model,每一列选中的索引值
		modelValue: {
			type: [Number, String, Boolean, Array],
			default: undefined,
		},

		/**
		 * 注意：这里是单向输出显示的value值，而不是modelValue的index索引值。
		 * 这里主要是为了方便表单上页面的显示。如果真要保存到数据库，你应该保存modelValue的值。
		 */
		modelStr: {
			type: [String],
			default: '',
		},
		//默认选中的索引值。
		defaultValue: {
			type: [Number, String, Boolean, Array],
			default: undefined,
		},
		//赋值和选值方式
		//name:名称模式赋值和选择
		//id:id模式赋值和选择
		//index:索引模式赋值和选择
		selectedModel: {
			type: String,
			default: 'id',
		},
		max: {
			type: Number,
			default: 99,
		},
		//数据。
		columns: {
			type: Array as PropType<Array<any>>,
			default: () => [],
		},
		//当前改变index项时，改变时执行的函数。如果返回false，将会阻止本次改变,可以是Promise
		//提供了即将改变的数据和将要改变到目标的数据
		//结构 为 from:{itemindex,levelIndex,data},to:{itemindex,levelIndex,data}。
		beforeChange: {
			type: [Boolean, Function],
			default: () => false,
		},
		//v-model:show来双向绑定显示和隐藏选择器。
		show: {
			type: [Boolean],
			default: false,
		},
		color: {
			type: String,
			default: 'primary',
		},
		linear: {
			type: String,
			default: '',
		},
		linearDeep: {
			type: String,
			default: 'light',
		},
		btnRound: {
			type: Number,
			default: 3,
		},
		round: {
			type: Number,
			default: 3,
		},
		height: {
			type: Number,
			default: 900,
		},
		immediateChange: {
			type: Boolean,
			default: false,
		},
		/** 是否嵌入弹层，开启后将在它的父组件内执行弹层。 */
		inContent: {
			type: Boolean,
			default: false,
		},
		//模式：单选或者多选multiple
		mode: {
			type: String,
			default: 'single',
		},
		timeout: Number,
		//是否加密
		cryptoEnabled: {
			type: Boolean,
			default: false
		},
		//是否脱敏
		desensitizeFlag: {
			type: Boolean,
			default: false
		},
		//是否防重复提交
		repeatEnabled: {
			type: Boolean,
			default: false
		},
		queryParams: {
			type: Object,
			default: () => { },
		},
		//查询附带参数
		searchParams: {
			type: Object,
			default() {
				return {
					tableName: 'sys_dict',
					resultList: [],
					queryList: [],
					pageNum: 1,
					pageSize: 20,
				};
			},
		},
		//查询url
		url: {
			type: String,
			default() {
				return '';
			},
		},
		//查询功能编号
		funcCode: {
			type: String,
			default() {
				return '';
			},
		},
		//查询数据字典字段
		dictField: {
			type: String,
			default() {
				return '';
			},
		},
		//查询主字段名称
		searchField: {
			type: String,
			default() {
				return '';
			},
		},
		/**禁用时，通过插槽点击时，不会触发显示本组件，适合表单 */
		disabled: {
			type: Boolean,
			default: false,
		},
		zIndex: {
			type: [Number, String],
			default: 999,
		},
	});
	const nodeLabel = computed(() => {
		if (props.fieldNames.bindLabel) {
			return props.fieldNames.bindLabel;
		}
		return props.fieldNames.label;
	});
	const nodeValue = computed(() => {
		if (props.fieldNames.bindValue) {
			return props.fieldNames.bindValue;
		}
		return props.fieldNames.value;
	});
	const showCity = ref(props.show);
	const myOptions = ref<any>(props.columns);
	const allList = ref([...props.columns]);
	const firstList = ref([]);
	const pagingList = ref([]);
	const paging = ref();
	const searchText = ref('');
	const aniover = ref(true);
	const value = ref<any>(null);
	const _strvalue = ref<any>(props.modelStr);
	const sysinfo = useWindowInfo()
	const _color = computed(() => {
		let color = props.color;
		if (props.followTheme && store.color) {
			color = store.color;
		}
		return color;
	});
	const radioClick = (item : any) => {
		myOptions.value = [item];
		if (typeof item == 'string') {
			_strvalue.value = item;
			value.value = item;
		} else {
			value.value = item[nodeValue.value];
			_strvalue.value = item[nodeLabel.value];
		}
	};
	const radioChange = (e : any, item : any) => {
		myOptions.value = [item];
		if (typeof item == 'string') {
			_strvalue.value = item;
		} else {
			_strvalue.value = item[nodeLabel.value];
		}
	};
	const checkboxClick = (item : any) => {
		if (!value.value) {
			value.value = [typeof item == 'string' ? item : item[props.fieldNames.value]];
			myOptions.value.push(item);
			return;
		}
		let valIndex = value.value.findIndex((val : any) => {
			if (typeof item == 'string') {
				return val == item;
			} else {
				return val == item[nodeValue.value];
			}
		});
		if (valIndex >= 0) {
			value.value.splice(valIndex, 1);
			let index = myOptions.value.findIndex((val : any) => {
				if (typeof item == 'string') {
					return val == item;
				} else {
					return val[nodeValue.value] == item[nodeValue.value];
				}
			});
			if (index >= 0) {
				myOptions.value.splice(index, 1);
			}
		} else {
			value.value.push(typeof item == 'string' ? item : item[props.fieldNames.value]);
			myOptions.value.push(item);
		}
		getStr(value.value);
	};
	const checkboxChange = (e : any, item : any) => {
		let index = myOptions.value.findIndex((val : any) => {
			if (typeof item == 'string') {
				return val == item;
			} else {
				return val[nodeValue.value] == item[nodeValue.value];
			}
		});
		if (e) {
			if (index < 0) {
				myOptions.value.push(item);
			}
		} else {
			if (index >= 0) {
				myOptions.value.splice(index, 1);
			}
		}
		getStr(value.value);
	};
	function onSearch() {
		uni.$tm.u.debounce(() => emits('search', paging.value?.reload()), 500);
	}
	const onQueryList = (pageNo : number, pageSize : number) => {
		query(pageNo, pageSize, false);
	};
	const query = (pageNo : number, pageSize : number, firstFlag : boolean) => {
		if (!props.lazy) {
			if (searchText.value) {
				let list = allList.value.filter((item) => (typeof item == 'string' ? item.indexOf(searchText.value) >= 0 : item[nodeLabel.value].indexOf(searchText) >= 0));
				paging.value?.setLocalPaging([...list]);
			} else {
				paging.value?.setLocalPaging(allList.value);
			}
			return;
		}
		let mySearchParams = Object.assign({}, props.searchParams);
		mySearchParams.pageNum = pageNo;
		mySearchParams.pageSize = pageSize;
		if (!mySearchParams.tableName) {
			mySearchParams.tableName = 'sys_dict';
		}
		let searchField = props.searchField;
		if (!searchField) {
			searchField = toLine(nodeLabel.value);
		}
		mySearchParams.keyName = nodeLabel.value;
		mySearchParams.valueName = nodeValue.value;
		mySearchParams.searchField = searchField;
		mySearchParams.searchText = searchText.value;
		mySearchParams[props.searchField] = searchText.value;
		if (props.queryParams) {
			mySearchParams = Object.assign(mySearchParams, props.queryParams);
		}
		if (firstFlag) {
			if (props.mode === 'multiple') {
				let idList = null;
				if (value.value) {
					idList = value.value;
				}
				mySearchParams[nodeValue.value + 'List'] = idList;
			} else {
				mySearchParams[nodeValue.value] = value.value;
			}
		}
		let config : any = {};
		if (props.timeout && props.timeout > 0) {
			config.timeout = props.timeout;
		}
		let searchUrl = $api.common.getDictSearchData.url;
		let headers = {} as any
		headers.cryptoEnabled = props.cryptoEnabled
		headers.repeatEnabled = props.repeatEnabled
		headers.desensitizeFlag = props.desensitizeFlag
		if (props.funcCode) {
			headers['func-code'] = props.funcCode;

			searchUrl = $api.common.send.url + props.funcCode;
		} else {
			if (props.url) {
				searchUrl = props.url;
			} else if (props.dictField) {
				searchUrl = $api.common.send.url + 'dict0011';
				headers['func-code'] = 'dict0011';
				mySearchParams.dictField = props.dictField;
			}
		}
		config.header = headers;
		http
			.post(searchUrl, mySearchParams, config)
			.then((res : any) => {
				if (!Array.isArray(res.result)) {
					if (firstFlag) {
						myOptions.value = res.result.list || [];
						firstList.value = res.result.list || [];
						defaultModerStrGet();
					} else {
						paging.value?.complete(res.result.list || []);
					}
				} else {
					if (firstFlag) {
						myOptions.value = res.result || [];
					} else {
						paging.value?.setLocalPaging(res.result || []);
					}
				}
			})
			.catch(() => {
				paging.value?.complete(false);
			});
	};
	onMounted(() => {
		// getIndexBymodel(_data.value, props.selectedModel, 0, props.defaultValue)
		if (props.modelValue && props.modelValue.length > 0) {
			setValue();
			if (props.lazy) {
				query(1, props.max, true);
			} else {
				defaultModerStrGet();
			}
		}
	});
	function setValue() {
		if (props.mode === 'multiple') {
			if (typeof props.modelValue == 'string') {
				let list = [];
				list.push(props.modelValue);
				value.value = list;
			} else {
				value.value = props.modelValue;
			}
		} else {
			value.value = props.modelValue;
		}
	}
	function defaultModerStrGet() {
		getStr(value.value);
		emits('update:modelStr', _strvalue.value);
	}
	//点击确认了地区。
	function confirm() {
		showCity.value = false;
		let selectList : any = [];
		if (myOptions.value && myOptions.value.length > 0) {
			if (props.mode === 'single') {
				if (value) {
					myOptions.value.forEach((item : any) => {
						if (typeof item == 'string') {
							if (item === value.value) {
								selectList.push(item);
							}
						} else {
							if (item[props.fieldNames.value] === value.value) {
								selectList.push(item);
							}
						}
					});
				}
			} else if (props.mode === 'multiple') {
				if (value.value && value.value.length > 0) {
					myOptions.value.forEach((item : any) => {
						value.value.forEach((valueItem : any) => {
							if (typeof item == 'string') {
								if (item === valueItem) {
									selectList.push(item);
								}
							} else {
								if (item[props.fieldNames.value] == valueItem) {
									selectList.push(item);
								}
							}
						});
					});
				}
			}
		}
    emits('update:modelStr', _strvalue.value);
    emits('confirm', value.value, selectList);
    emits('update:modelValue', value.value);
		emits('update:show', showCity.value);
	}
	function cancel() {
		if (props.mode === 'multiple') {
			if (typeof props.modelValue == 'string') {
				let list = [];
				list.push(props.modelValue);
				value.value = list;
			} else {
				value.value = props.modelValue;
			}
		} else {
			value.value = props.modelValue;
		}
		showCity.value = false;
		emits('update:show', showCity.value);
		emits('cancel');
	}

	//弹层打开时触发。
	function drawerOpen() {
		emits('open');
	}
	const dHeight = computed(() => {
		return props.height + sysinfo.bottomSafe;
	});

	const getStr = (value : any) => {
		let str : any = '';
		if (myOptions.value && myOptions.value.length > 0) {
			if (props.mode === 'single') {
				if (!value) {
					_strvalue.value = '';
					return;
				}
				let list = myOptions.value.filter((item : any) => {
					if (typeof item == 'string') {
						return item === value;
					} else {
						return item[props.fieldNames.value] === value;
					}
				});
				if (list && list.length > 0) {
					if (typeof list[0] == 'string') {
						str = list[0];
					} else {
						str = list[0][props.fieldNames.label];
					}
				}
			} else if (props.mode === 'multiple') {
				if (!value || value.length <= 0) {
					_strvalue.value = '';
					return;
				}
				myOptions.value.forEach((item : any) => {
					value.forEach((valueItem : any) => {
						if (typeof item == 'string') {
							if (item === valueItem) {
								if (str) {
									str = str + ',' + item;
								} else {
									str = +item;
								}
							}
						} else {
							if (item[props.fieldNames.value] == valueItem) {
								if (str) {
									str = str + ',' + item[props.fieldNames.label];
								} else {
									str = item[props.fieldNames.label];
								}
							}
						}
					});
				});
			}
			_strvalue.value = str;
		} else {
			_strvalue.value = '';
		}
	};
	watch(
		() => props.modelValue,
		(val) => {
			if (props.mode === 'multiple') {
				if (typeof val == 'string') {
					let list = [];
					list.push(val);
					value.value = list;
				} else {
					value.value = val;
				}
			} else {
				value.value = val;
			}
		},
		{ deep: true }
	);
	watch(
		() => searchText.value,
		(val) => {
			onSearch();
		},
		{ deep: true }
	);
	watch(
		() => props.queryParams,
		() => {
			if (props.lazy) {
				query(1, props.max, true);
			}
		},
		{ deep: true }
	);
	watch(
		() => props.searchParams,
		() => {
			if (props.lazy) {
				query(1, props.max, true);
			}
		},
		{ deep: true }
	);
	watch(
		() => props.columns,
		(val) => {
			nextTick(() => {
				if (props.columns) {
					allList.value = [...props.columns];
					paging.value?.reload();
					defaultModerStrGet();
				}
			});
		},
		{ immediate: true }
	);
	watch(
		() => props.show,
		(val) => {
			showCity.value = val;
		},
		{ deep: true }
	);
</script>

<style scoped></style>